{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[this doc on github](https://github.com/dotnet/interactive/tree/main/samples/notebooks/fsharp/Docs)\n",
    "\n",
    "# Displaying Output in an F# notebook"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This article describes how to display output results in F# notebooks.\n",
    "\n",
    "When writing F# in a .NET notebook, you can write code similar to how you would with the F# Interactive tool."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "1 + 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The last value in a cell has its output displayed. When you end a cell with an expression evaluation like this, it is the return value of the cell. There can only be a single return value for a cell. If you add more code after a return value expression, you'll see a compile error. \n",
    "\n",
    "Here is another example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "let r = System.Random()\n",
    "r.Next(0,10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also evaluate a string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "\"Hello, world!\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### Using Console Output\n",
    "\n",
    "You can display information without using the return value. The most intuitive way is to write to the console:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "System.Console.WriteLine(\"Hello, world!\")\n",
    "printfn \"Hello, world!\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also use `%A` printing to print structured values:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "printfn \"%120A\" [ for i in 1 .. 30 -> [ 1 .. i ]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Console output produced after the completion of the cell execution (e.g. from background threads or asynchronous processing) may be ignored."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using `display`\n",
    "\n",
    "A more familiar API for many notebook users would be the `display` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "display(\"Hello, world!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Many outputs are automatically formatted as HTML by `display` or output-value formatting.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Each call to `display` writes an additional display data value to the notebook.\n",
    "You can also update an existing displayed value by calling `Update` on the object returned by a call to `display`.\n",
    "\n",
    "In some environments such as Jupyter Lab, only updates made during the execution of the cell are applied.  Any updates made by background processing after the completion of\n",
    "execution may be ignored."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "let fruitOutput = display(\"Let's get some fruit!\");\n",
    "let basket = [| \"apple\"; \"orange\"; \"coconut\"; \"pear\"; \"peach\" |]\n",
    "\n",
    "for fruit in basket do\n",
    "    System.Threading.Thread.Sleep(1000);\n",
    "    let updateMessage = sprintf \"I have 1 %s\" fruit\n",
    "    fruitOutput.Update(updateMessage)\n",
    "\n",
    "System.Threading.Thread.Sleep(1000);\n",
    "\n",
    "fruitOutput.Update(basket);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Displaying HTML\n",
    "\n",
    "\n",
    "\n",
    "To display arbitrary HTML, the helper function `HTML` can be used.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "HTML( \"<b style=\\\"color:blue\\\">Hello!</b>\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "HTML can be specified using any DSL that generates ASP.NET Core `IHtmlContent`.  The `Html` module contains an F# DSL for HTML specification similar to [Giraffe.ViewEngine](https://github.com/giraffe-fsharp/Giraffe.ViewEngine#html-elements-and-attributes) that does this. For example:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "open Html\n",
    "\n",
    "let indexView =\n",
    "    div [] [\n",
    "      h4 [] [ str \"I love F#\" ]\n",
    "      p [ _class \"some-css-class\"; _id \"someId\" ] [\n",
    "          b  [] [str \"Hello\" ]\n",
    "          str \" \"\n",
    "          i [] [str \"World\"]\n",
    "      ]\n",
    "    ]\n",
    "\n",
    "display(indexView)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Executing Javascript\n",
    "\n",
    "The helper function `Javascript` executes Javascript directly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "Javascript(@\"alert(\"\"Hello!\"\");\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Defining CSS"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `CSS` function can be used to add CSS styling to the host HTML system. Here are some examples:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "fsharp"
    }
   },
   "outputs": [],
   "source": [
    "CSS \"h2 { color: darkslategrey; }\""
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".NET (F#)",
   "language": "F#",
   "name": ".net-fsharp"
  },
  "language_info": {
   "file_extension": ".fs",
   "mimetype": "text/x-fsharp",
   "name": "C#",
   "pygments_lexer": "fsharp",
   "version": "4.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}